//f_Interal.cpp//

#include "f_interval.hpp"


//-----------------Standard IO Functions-------------------//
std::ostream& operator << (std::ostream& s, const f_interval& a)
{
    s << '[' << a.inf << ',' << -a.nsup << ']';
    return s;
}

std::string & operator << (std::string & s, const f_interval & a)
{
    s+='[';
    s << a.inf;
    s += ',';
    s << -a.nsup;
    s+=']';
    return s;   
}

//-----------------END of Standard IO Functions-------------------//

//----------------Mathematical Functions-------------------//

//Standard algebric addition operation
f_interval operator +(const f_interval &a, const f_interval &b)
{
    f_interval help;
    help.inf = a.inf + b.inf;
    help.nsup = a.nsup + b.nsup;
    return help;    
}

//Standard algebric subtraction operation
f_interval operator -(const f_interval &a, const f_interval &b)
{
    f_interval help;
    help.inf = a.inf + b.nsup;
    help.nsup = a.nsup + b.inf;
    return help; 
}

//Standard algebric multiplication operation
f_interval operator *(const f_interval &a, const f_interval &b)
{
    f_interval prod;
    real help;
    
    if(a.inf>=0.0)
        if(b.inf>=0.0)
        {
            prod.inf = a.inf * b.inf;
            prod.nsup = a.nsup * (-b.nsup);         
        }
        else if(b.nsup >= 0.0)
        {
            prod.inf = (-a.nsup) * b.inf;
            prod.nsup = a.inf * b.nsup;
        }
        else
        {
            prod.inf = (-a.nsup) * b.inf;
            prod.nsup = (-a.nsup) * b.nsup;
        }
    else if (a.nsup >= 0.0)
        if (b.inf >= 0.0)
        {
            prod.inf = a.inf * (-b.nsup);
            prod.nsup = a.nsup * b.inf;
        }
        else if(b.nsup >= 0.0)
        {
            prod.inf = a.nsup * b.nsup;
            prod.nsup = a.inf * (-b.inf);
        }
        else
        {
            prod.inf = (-a.inf) * b.nsup;
            prod.nsup = (-a.inf) * b.inf;            
        }
    else
        if(b.inf >= 0.0)
        {
            prod.inf = a.inf * (-b.nsup);
            prod.nsup = a.nsup * (-b.nsup);
        }
        else if(b.nsup >= 0.0)
        {
            prod.inf = a.nsup * (-b.inf);
            prod.nsup = a.inf * (-b.inf);
        }
        else
        {
            prod.inf = a.inf * (-b.nsup);
            help = a.nsup * (-b.inf);
            if(help < prod.inf) prod.inf = help;
            prod.nsup = a.inf * (-b.inf);
            help = a.nsup * (-b.nsup);
            if(help < prod.nsup) prod.nsup = help;
        }
    return prod;
}

/*Standard algebric division operation
f_interval operator /(const f_interval &a, const f_interval &b)
{
    
    
}*/


//Standard real+interval algebric addition. (real+f_interval)
f_interval operator +(const real &a, const f_interval &b)
{
    f_interval help;
    help.inf = a + b.inf;
    help.nsup = -a + b.nsup;
    return help;
}

//Standard real+interval algebric addition. (f_interval+real)
f_interval operator +(const f_interval &a, const real &b)
{
    f_interval help;
    help.inf = a.inf + b;
    help.nsup = a.nsup + -b;
    return help;
}

//Standard real-interval algebric subtraction. (real-f_interval)
f_interval operator -(const real &a, const f_interval &b)
{
    f_interval help;
    help.inf = a + b.nsup;
    help.nsup = -a + b.inf;
    return help;
}

//Standard real+interval algebric subtraction. (f_interval-real)
f_interval operator -(const f_interval &a, const real &b)
{
    f_interval help;
    help.inf = a.inf - b;
    help.nsup = a.nsup - -b;
    return help;
}

//Standard real*interval algebric multiplication (real*f_interval)
f_interval operator *(const real &a, const f_interval &b)
{
    f_interval help;
    if(a == 0)
    {
        help.inf = 0.0;
        help.nsup = 0.0;
    }
    else if (a > 0)
        {
            help.inf = a * b.inf;
            help.nsup = a * b.nsup;
        }
        else
        {
            help.inf = -a * b.nsup;
            help.nsup = -a * b.inf;
        }
        
    return help;
}

//Standard real*interval algebric multiplication (f_interval*real)
f_interval operator *(const f_interval &a, const real &b)
{
    f_interval help;
    if(b == 0)
    {
        help.inf = 0.0;
        help.nsup = 0.0;
    }
    else if (b > 0)
        {
            help.inf = a.inf * b;
            help.nsup = a.nsup * b;
        }
        else
        {
            help.inf = a.nsup * -b;
            help.nsup = a.inf * -b;
        }
        
    return help;   
}
